<template>
  <n-config-provider :theme="darkTheme" :theme-overrides="naiveTheme"
                     class="w-full h-full p-4 bg-main-400 rounded-xl shadow-2xl shadow-main-400"
  >
    <div v-if="title" class="font-bold text-xl p-2">{{ title }}</div>

    <div v-if="isShowTool" class="flex gap-2 my-2 w-full">
      <slot />
      <div class="grow" />
      <div v-for="item in renderTools">
        <template v-if="item.type === 'selector'">
          <n-select :options="item?.options || []" class="w-32" :placeholder="item.placeholder || '请选择'"
                    :on-update:value="(value) => onSelectorChange(item.key, value)"
          />
        </template>
      </div>
    </div>

    <n-data-table bordered :columns="renderColumns" max-height="100%"
                  :data="renderData" size="small" class="w-full border border-secondary-600" :scroll-x="1800"
    />

    <div class="justify-end flex pt-3">
      <n-pagination v-model:page="page" :page-count="pages" simple :on-update:page="onSkip" />
    </div>
  </n-config-provider>
</template>

<script lang="ts" setup>
import { naiveTheme } from '../../shared/theme/naive_theme'
import { uniq } from 'lodash'
import {
  NDataTable, DataTableColumns, NButton, SelectOption,
  NSelect, NConfigProvider, darkTheme, NPagination, NTag
} from 'naive-ui'
import { PropType, onMounted, ref, h, reactive } from 'vue'
import { defaultLimit } from '../../shared/utils/default'

export interface Column {
  title?: string,
  key?: string,
  width?: number,
  buttons?: string[],
  tags?: Record<string, 'info' | 'primary' | 'warning' | 'error' | 'success'>
}

export interface Tool {
  type: 'selector',
  key?: string,
  placeholder?: string,
  options?: SelectOption[]
}

const props = defineProps({
  isShowTool: {
    type: Boolean,
    required: false,
    default: () => false
  },

  title: {
    type: String,
    required: false,
    default: () => ''
  },

  pages: {
    type: Number,
    required: false,
    default: () => 100
  },

  columns: {
    type: Array as PropType<Column[]>,
    required: true
  },

  tools: {
    type: Array as PropType<Tool[]>,
    required: false,
    default: () => []
  },

  provider: {
    type: Function as PropType<(skip: number, params?: Record<string, any>) => Promise<any[]>>,
    required: true
  },

  buttonClick: {
    type: Function,
    required: false,
    default: () => null
  }
})

const params = reactive<Record<string, any>>({})

const renderData = ref<any>([])
const renderColumns = ref<DataTableColumns<any>>([])
const renderTools = ref<Tool[]>([])
async function init() {
  renderData.value = await props.provider(0, params)

  renderColumns.value = props.columns.map(column => {
    const output: any = {
      title: column?.title || '',
      width: column?.width || 100,
      key: column?.key || '',
      sorter: 'default'
    }

    if (column?.tags) {
      const tags = column?.tags
      output.render = (row) => {
        const arr = Array.isArray(row[output.key]) ? row[output.key] : [row[output.key]]
        return arr.map(item => {
          return h(
            NTag,
            {
              style: { marginRight: '6px' },
              type: tags[item] || 'primary',
              bordered: false,
              size: 'small'
            },
            { default: () => item }
          )
        })
      }
    }

    if (column?.buttons) {
      const buttons = column.buttons
      output.render = (row, index: number) => {
        return buttons.map(button => {
          return h(
            NButton,
            {
              style: { marginRight: '6px' },
              type: 'primary',
              ghost: true,
              size: 'small',
              onClick: () => props.buttonClick(button, row, index)
            },
            { default: () => button }
          )
        })
      }
      output.fixed = 'right'
      output.width = column?.width
      output.title = '操作'
    }

    return output
  })

  renderTools.value = props.tools.map(tool => {
    const output: Tool = { type: tool.type, key: tool.key }

    if (tool.type === 'selector' && tool.key) {
      output.options = uniq(renderData.value.map(x => x[tool.key!])).map((x: string) => ({ label: x, value: x }))
    }

    return output
  })
}

const page = ref(1)
async function onSkip(value: number) {
  renderData.value = await props.provider((value - 1) * defaultLimit, params)
  page.value = value
}

async function onSelectorChange(key, value) {
  params[key] = value
  renderData.value = await props.provider((page.value - 1) * defaultLimit, params)
}

onMounted(() => init())

</script>

<style>
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
</style>
